<?php

namespace Xrfg\Api\Trading\Spot\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;
use Xrfg\Core\Trading\Account\Models\Account;
use Xrfg\Core\Trading\Spot\Models\Order;
use Xrfg\Api\Trading\Spot\Repositories\OrderBook;

class CancelOrderJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    public $id;
    private $order;

    public function __construct($id)
    {
        $this->id = $id;
    }

    public function handle(OrderBook $orderBook)
    {
        try {
            DB::transaction(function () {
                $this->order = Order::lockForUpdate()->find($this->id);
                if (Order::STATUS_NEW !== $this->order->status) {
                    return;
                }
                // 修改订单状态
                $this->order->status = Order::STATUS_CANCELED;
                $this->order->save();

                // 解冻账户
                $returnNumber = bcsub($this->order->number, $this->order->deal_number);
                if (Order::SIDE_BUY === $this->order->side) {
                    /** @var Account $account */
                    $account = Account::lockForUpdate()
                        ->where('user_id', $this->order->user_id)
                        ->where('coin_id', $this->order->market_id)
                        ->first();
                    if (Order::TYPE_MARKET === $this->order->type) {
                        $return = $returnNumber;
                    } else {
                        $return = bcmul($returnNumber, $this->order->price);
                    }
                } else {
                    /** @var Account $account */
                    $account = Account::lockForUpdate()
                        ->where('user_id', $this->order->user_id)
                        ->where('coin_id', $this->order->coin_id)
                        ->first();
                    $return = $returnNumber;
                }

                // 生成资金流水记录
                $account->availableIncrement($return);
                $account->disabledDecrement($return);
                $account->proofId = [$this->order->id, Order::CLASS_ID, Order::SIDE_BUY == $this->order->side ? Order::OP_BUY_CANCELED : Order::OP_SELL_CANCELED];
                $account->save();
            });
        } catch (Throwable $exception) {
            Log::error($exception);

            return;
        }

        $orderBook->remove($this->order);
    }
}
